# -*- coding: utf-8 -*-

import sys
import importlib
import xml.sax
import ppc
import ppc.pipe
import ppc.modules


"""
任务常量定义
"""
_TASK_ = {
    'entry_pipe_id' : 'entry',
    'config_name'   : 'config',
    'config_path'   : 'task/{0}/{1}.xml',
    'module_path'   : 'task.{0}'
}

# 用户自定义的任务目录的模块加载
_TASK_MODULE_ = None


class Task(ppc.Singleton):
    """
    Task类
    对数据进行一系列的转换，称作执行一个Task。一个Task由多个Pipe组件组合而成，Task控制和协调各个Pipe组件的执行。
    """

    def __init__(self, name):
        self.name = name
        self.pipes = {}

    def parse(self):
        argv = ppc.CmdlineArguments.instance
        config_name = argv['config'] if argv['config'] else _TASK_['config_name']
        config_path = _TASK_['config_path'].format(self.name, config_name)
        xml.sax.parse(config_path, _TaskXmlParser())

    def addPipe(self, pipe):
        self.pipes[pipe.id] = pipe

    def run(self):
        self.pipes[_TASK_['entry_pipe_id']].send(None)


class _TaskXmlParser(xml.sax.ContentHandler):
    """
    Task的xml解析
    """

    def __init__(self):
        self.maker = None

        global _TASK_MODULE_
        try:
            _TASK_MODULE_ = importlib.import_module(
                _TASK_['module_path'].format(Task.instance.name))
        except ImportError:
            pass

    def startElement(self, tag, attrs):
        if tag == 'pipe':
            self.maker = _PipeMaker(attrs)
        elif self.maker is not None:
            self.maker.startParam(tag, attrs)

    def endElement(self, tag):
        if tag == 'pipe':
            Task.instance.addPipe(self.maker.pipe)
            self.maker = None
        elif self.maker is not None:
            self.maker.endParam(tag)

    def characters(self, content):
        if self.maker is not None:
            self.maker.setParamValue(content)


class _TaskXmlError(Exception):
    """
    任务配置的xml文件错误异常
    """

    def __init__(self, *args, **kwargs):
        super(_TaskXmlError, self).__init__(*args, **kwargs)


class _PipeMaker(object):
    """
    创建Pipe的类
    """

    def __init__(self, attrs):
        d = {}
        for k, v in attrs.items():
            d[k] = v

        if 'id' not in d:
            raise _TaskXmlError('xml解析错误，pipe节点需要设置id属性')
        if 'module' not in d:
            raise _TaskXmlError('xml解析错误，pipe节点需要设置module属性')

        if _TASK_MODULE_ and hasattr(_TASK_MODULE_, d['module']):
            pipe_class = getattr(_TASK_MODULE_, d['module'])
        elif hasattr(ppc.modules, d['module']):
            pipe_class = getattr(ppc.modules, d['module'])
        else:
            pipe_class = ppc.pipe.Pipe

        target = [] if 'target' not in d else d['target'].split(',')
        self.pipe = pipe_class(d['id'], target)

        self.parameter = None

    def startParam(self, tag, attrs):
        if self.parameter is not None:
            raise _TaskXmlError('xml解析错误，pipe节点的子元素不支持嵌套')

        self.parameter = ppc.pipe.Parameter(tag, attrs.items())

    def endParam(self, tag):
        self.pipe.addParameter(self.parameter)
        self.parameter = None

    def setParamValue(self, content):
        if self.parameter is not None:
            # 对于多行的内容，需要累加，解析器是每读一行赋值一次
            if self.parameter.ohas('value'):
                v = self.parameter.oget('value')
                self.parameter.oset('value', v + content)
            else:
                self.parameter.oset('value', content)
